
#include "util.h"
#include "quickSort.h"
#include "basicSort.h"
#include "shellSort.h"
#include "testComm.h"
#include <iostream>
#include "util.h"
#include "lsdSort.h"

#if 1
#define ARRAY_SZ    (30000)
#else
#define ARRAY_SZ    (300)
#endif

#define PRT_ARRAY_CTX 1


typedef void (*sort_func)(int a[], int n);

struct sort_func_info
{
    sort_func func;
    const char *desc;
    const char *extra;
};

static struct sort_func_info funs[] = 
{
    {bubbleSort, "bubble-Ascending", "std"},
    {bubbleSort1,"bubble-Descending", "std"},
    {insertSort, "insert-Ascending","std"},
    {insertSort1, "insert-Descending","std"},
    {insertSort2, "insert-Ascending", "self"}
};

static void basic_test(void)
{
    int sz = 50;
    int r;

    int *a = nullptr, *b = nullptr;
    int *c = nullptr, *d = nullptr;
    int *e = nullptr;

    a = get_array_mem(sz);
    UTIL_ASSERT(a != nullptr);

    b = get_array_mem(sz);
    UTIL_ASSERT(b != nullptr);

    c = get_array_mem(sz);
    UTIL_ASSERT(c != nullptr);

    d = get_array_mem(sz);
    UTIL_ASSERT(d != nullptr);

    e = get_array_mem(sz);
    UTIL_ASSERT(e != nullptr);

    r = gen_array(a, sz);
    std::cout << "gen array ret: " << r << std::endl;
    
    std::cout << "array a: " << std::endl;
    prt_array(a, sz);

    std::cout << "array b: " << std::endl;
    copy_array(b, a, sz);
    prt_array(b, sz);

    std::cout << "array c: " << std::endl;
    copy_array(c, a, sz);
    prt_array(c, sz);

    std::cout << "array d: " << std::endl;
    copy_array(d, a, sz);
    prt_array(d, sz);


    std::cout << "array e: " << std::endl;
    copy_array(e, a, sz);
    prt_array(e, sz);


    struct sort_func_info f = funs[0];

    std::cout << f.desc << std::endl;
    f.func(a, sz);
    prt_array(a, sz);

    f = funs[2];

    std::cout << f.desc << std::endl;
    f.func(b, sz);
    prt_array(b, sz);

    f = funs[1];

    std::cout << f.desc << std::endl;
    f.func(c, sz);
    prt_array(c, sz);

    f =funs[3];
    std::cout << f.desc << std::endl;
    f.func(d, sz);
    prt_array(d, sz);

    f =funs[4];
    std::cout << f.desc << std::endl;
    f.func(e, sz);
    prt_array(e, sz);

    destroy_array_mem(a);
    destroy_array_mem(b);
    destroy_array_mem(c);
    destroy_array_mem(d);
    destroy_array_mem(e);

}

static int basic_sort_test(void)
{

    int *a = nullptr, *b = nullptr;
    int *c = nullptr, *d = nullptr;
    int ret;
    struct sort_test_t test_sort;

    a = get_array_mem(ARRAY_SZ);

    test_sort.f = shellSort;
    test_sort.description = (const char *)"Shell";
    test_sort.func_param1 = a;
    test_sort.func_param2 = ARRAY_SZ;
    test_sort.repeat = 1;

    
    UTIL_ASSERT(a != nullptr);
    //Descending completely
    for(int i = 0; i < ARRAY_SZ; i++)
    {
        a[ARRAY_SZ-1-i] = i+1;
    }
    
    xcopy_array(&b, a, ARRAY_SZ);
    xcopy_array(&d, a, ARRAY_SZ);
    xcopy_array(&c, a, ARRAY_SZ);
    
    ret = time_taken_api(&test_sort);
    std::cout << "api ret : " << ret << std::endl;
    std::cout << test_sort.description << " take : " << test_sort.elapsed << " ms" << std::endl;


    test_sort.f = insertionSort;
    test_sort.description = (const char *)"Insertion";
    test_sort.func_param1 = b;

    ret = time_taken_api(&test_sort);
    std::cout << "api ret : " << ret << std::endl;
    std::cout << test_sort.description << " take : " << test_sort.elapsed << " ms" << std::endl;

    test_sort.f = bubbleSort;
    test_sort.description = (const char *)"Bubble";
    test_sort.func_param1 = c;

    ret = time_taken_api(&test_sort);
    std::cout << "api ret : " << ret << std::endl;
    std::cout << test_sort.description << " take : " << test_sort.elapsed << " ms" << std::endl;

    test_sort.f = insertSort;
    test_sort.description = (const char *)"insertSort";
    test_sort.func_param1 = d;

    ret = time_taken_api(&test_sort);
    std::cout << "api ret : " << ret << std::endl;
    std::cout << test_sort.description << " take : " << test_sort.elapsed << " ms" << std::endl;

    ret = util_memcmp((void *)a, (void *)b, ARRAY_SZ * sizeof(int)); 
    std::cout << " a compare with b ret: " << ret << std::endl;
    ret = util_memcmp((void *)a, (void *)c, ARRAY_SZ * sizeof(int)); 
    std::cout << " a compare with c ret: " << ret << std::endl;
    ret = util_memcmp((void *)a, (void *)d, ARRAY_SZ * sizeof(int)); 
    std::cout << " a compare with d ret: " << ret << std::endl;
    UTIL_ASSERT(a[0] == 0+1); 
    UTIL_ASSERT(b[15] == 15+1); 
    UTIL_ASSERT(c[29999] == 29999+1); 
    UTIL_ASSERT(c[345] == 345+1); 
    destroy_array_mem(a);
    destroy_array_mem(b);
    destroy_array_mem(c);
    destroy_array_mem(d);
    return 0;
}

static void quick_sorts_test(void)
{
    int a[64];
    int i, n;
    int *b, *c;

    n = sizeof(a)/sizeof(a[0]);
    
    for(i = 0; i < n; i++)
    {
        a[i] = n - i;
    }

    quickSort(a, n);

    prt_array(a, n);

    
    b = get_array_mem(58);
    gen_array(b, 58);
    quickSort(b, 58);
    prt_array(b, 58);

    c = get_array_mem(128);
    gen_array(c, 128);
    quickSort(c, 128);
    prt_array(c, 128);

    destroy_array_mem(b);
    destroy_array_mem(c);

}

static void lsd_sort_ints_test(void)
{
    int a[] = 
    { 56987124, 57984127,58971247, 24715978,41298745,
      49817524, 27149875, 87415241, 87415214, 24178759
    }; 
    prt_array(a, 10);
    lsdSortInts(a, 10);
    prt_array(a, 10);
}

void test_sorts_main(void)
{
    //quick_sorts_test();
    //basic_test();
    //basic_sort_test();
    lsd_sort_ints_test();
}

